/**
 * 系统通知管理模块
 * 使用函数式编程处理系统级通知
 * 支持多平台适配(Windows, macOS, Linux)
 * @author LYC
 * @date 2025-09-20
 */

import { Notification, BrowserWindow, app } from 'electron'
import { resolve } from 'path'

/**
 * 通知配置接口
 */
export interface NotificationConfig {
  title: string
  body: string
  icon?: string
  silent?: boolean
  timeoutType?: 'default' | 'never'
  urgency?: 'normal' | 'critical' | 'low'
  tag?: string
  subtitle?: string
  // 增加支持的配置项
  hasReply?: boolean
  replyPlaceholder?: string
  sound?: string
  closeButtonText?: string
  actions?: Array<{ type: 'button'; text: string }>
}

/**
 * 通知响应处理函数类型
 */
export type NotificationHandler = (event: Electron.Event) => void

/**
 * 通知响应处理器映射
 */
export interface NotificationHandlerMap {
  show?: NotificationHandler
  click?: NotificationHandler
  close?: NotificationHandler
  reply?: (event: Electron.Event, reply: string) => void
  action?: (event: Electron.Event, index: number) => void
}

/**
 * 检查是否有通知权限（平台特定）
 */
export const checkNotificationPermission = async (): Promise<boolean> => {
  if (process.platform === 'darwin') {
    try {
      // macOS需要检查通知权限
      if (!Notification.isSupported()) {
        console.warn('系统不支持通知')
        return false
      }

      // Electron 22+中，检查通知权限 - 不限于已打包的应用
      if ('requestPermission' in Notification) {
        console.log('尝试请求通知权限...')
        // 主动请求权限
        try {
          const permission = await (
            Notification as { requestPermission: () => Promise<string> }
          ).requestPermission()
          console.log('通知权限状态:', permission)
          return permission === 'granted'
        } catch (err) {
          console.warn('请求通知权限失败:', err)
        }
      }

      // 尝试发送一个测试通知来触发权限请求
      try {
        console.log('尝试发送测试通知以触发权限请求')
        const testNotification = new Notification({
          title: '请求通知权限',
          body: '请允许应用发送通知',
          silent: true
        })
        testNotification.show()
        // 立即关闭
        setTimeout(() => testNotification.close(), 500)
      } catch (err) {
        console.warn('测试通知发送失败:', err)
      }

      return true
    } catch (error) {
      console.warn('无法检查macOS通知权限:', error)
      return true
    }
  } else if (process.platform === 'win32') {
    // Windows平台没有权限API，但需要确保AppUserModelID已设置
    if (!app.isPackaged) {
      // 开发模式下不检查
      return true
    }
    return true
  }

  // Linux和其他平台默认允许
  return true
}

/**
 * 设置Windows平台特定的通知配置
 */
export const setupWindowsNotification = (): void => {
  if (process.platform === 'win32') {
    // 设置Windows应用ID，确保通知正常工作
    app.setAppUserModelId(app.getName())
  }
}

/**
 * 平台特定的配置处理
 */
export const processPlatformSpecificConfig = (config: NotificationConfig): NotificationConfig => {
  const processedConfig = { ...config }

  if (process.platform === 'darwin') {
    // macOS平台特定处理

    // macOS对通知内容长度有限制，超过256字节会被截断
    if (processedConfig.body && processedConfig.body.length > 256) {
      processedConfig.body = processedConfig.body.substring(0, 253) + '...'
    }

    // 确保图标路径在macOS上有效
    if (processedConfig.icon) {
      try {
        console.log('通知原始图标路径:', processedConfig.icon)

        // 检查是否是webpack资源路径
        if (processedConfig.icon.includes('asset:')) {
          // 如果是webpack资源路径，尝试使用本地资源
          const appPath = app.getAppPath()
          processedConfig.icon = resolve(appPath, '../../resources/Logo.png')
          console.log('使用本地资源路径:', processedConfig.icon)
        } else if (!processedConfig.icon.startsWith('/')) {
          // 其他相对路径转为绝对路径
          processedConfig.icon = resolve(processedConfig.icon)
          console.log('转换为绝对路径:', processedConfig.icon)
        }

        // macOS上通知的图标必须是.png格式且大小合适
        if (!processedConfig.icon.toLowerCase().endsWith('.png')) {
          console.warn('macOS通知图标需要是PNG格式，将使用默认应用图标')
          delete processedConfig.icon
        }

        // 在macOS上设置特殊配置以促使通知显示
        if (!processedConfig.subtitle) {
          processedConfig.subtitle = '请点击查看' // macOS特有属性
        }

        // 确保通知声音开启 (macOS)
        if (processedConfig.silent === undefined) {
          processedConfig.silent = false
        }
      } catch (error) {
        console.error('处理通知图标路径失败:', error)
        delete processedConfig.icon
      }
    }
  } else if (process.platform === 'win32') {
    // Windows平台特定处理

    // Windows上建议始终设置timeoutType
    if (!processedConfig.timeoutType) {
      processedConfig.timeoutType = 'default'
    }

    // Windows 10上支持的操作按钮
    if (processedConfig.actions && processedConfig.actions.length > 3) {
      // Windows最多支持3个操作按钮
      processedConfig.actions = processedConfig.actions.slice(0, 3)
    }
  } else if (process.platform === 'linux') {
    // Linux平台特定处理

    // 某些Linux发行版可能不支持所有功能，简化配置
    delete processedConfig.subtitle
    delete processedConfig.closeButtonText

    // 确保图标路径在Linux上有效
    if (processedConfig.icon) {
      processedConfig.icon = resolve(processedConfig.icon)
    }
  }

  return processedConfig
}

/**
 * 创建通知的纯函数
 */
export const createNotification = (config: NotificationConfig): Notification => {
  // 应用平台特定的处理
  const processedConfig = processPlatformSpecificConfig(config)

  try {
    // 使用类型断言来解决Electron类型定义不完整的问题
    const notificationOptions = {
      title: processedConfig.title,
      body: processedConfig.body,
      icon: processedConfig.icon,
      silent: processedConfig.silent,
      timeoutType: processedConfig.timeoutType,
      urgency: processedConfig.urgency,
      subtitle: processedConfig.subtitle,
      hasReply: processedConfig.hasReply,
      replyPlaceholder: processedConfig.replyPlaceholder,
      sound: processedConfig.sound,
      closeButtonText: processedConfig.closeButtonText,
      actions: processedConfig.actions
    }

    console.log(
      '创建通知配置:',
      JSON.stringify(
        {
          title: processedConfig.title,
          body: processedConfig.body,
          icon: processedConfig.icon ? '(已设置)' : '(未设置)',
          silent: processedConfig.silent
        },
        null,
        2
      )
    )

    const notification = new Notification(
      notificationOptions as Electron.NotificationConstructorOptions
    )

    // 添加调试事件
    notification.on('show', () => {
      console.log('通知已显示:', processedConfig.title)
      console.log(`请检查系统通知中心是否有通知 - ${new Date().toLocaleTimeString()}`)
    })

    notification.on('click', () => {
      console.log('通知被点击:', processedConfig.title)
    })

    notification.on('close', () => {
      console.log('通知被关闭:', processedConfig.title)
    })

    // Electron的Notification没有error事件，只是为了调试，这里移除
    // 可能的事件有: show, click, close, reply, action

    return notification
  } catch (error) {
    console.error('创建通知失败:', error)

    // 降级处理：使用基本配置重试
    return new Notification({
      title: processedConfig.title,
      body: processedConfig.body,
      icon: processedConfig.icon
    })
  }
}

/**
 * 注册通知事件监听器的纯函数
 */
export const registerNotificationListeners = (
  notification: Notification,
  handlers: NotificationHandlerMap
): void => {
  if (handlers.show) {
    notification.on('show', handlers.show)
  }

  if (handlers.click) {
    notification.on('click', handlers.click)
  }

  if (handlers.close) {
    notification.on('close', handlers.close)
  }

  if (handlers.reply) {
    notification.on('reply', handlers.reply)
  }

  if (handlers.action) {
    notification.on('action', handlers.action)
  }
}

/**
 * 发送通知到渲染进程的纯函数
 */
export const sendNotificationToRenderer = (
  window: BrowserWindow | null,
  channel: string,
  notification: NotificationConfig
): void => {
  if (window && !window.isDestroyed()) {
    window.webContents.send(channel, notification)
  }
}

/**
 * 通知管理器类（函数式风格）
 */
export class NotificationManager {
  private static instance: NotificationManager
  private activeNotifications: Map<string, Notification> = new Map()
  private defaultIcon: string | undefined
  private isAppFocused: boolean = true
  private isDoNotDisturbMode: boolean = false

  private constructor() {
    // 初始化平台特定配置
    this.initializePlatformSpecific()
  }

  /**
   * 初始化平台特定配置
   */
  private initializePlatformSpecific = (): void => {
    // 在Windows平台上设置AppUserModelID
    setupWindowsNotification()

    // 监听系统免打扰模式变化（如果支持）
    if (process.platform === 'darwin') {
      try {
        this.checkDoNotDisturbMode()
      } catch (error) {
        console.warn('无法检查系统免打扰模式:', error)
      }
    }
  }

  /**
   * 检查系统免打扰模式
   */
  private checkDoNotDisturbMode = (): void => {
    if (process.platform === 'darwin') {
      try {
        // 真实实现中，这里应该使用native模块如macos-notification-state
        // const { getDoNotDisturb } = require('macos-notification-state');
        // this.isDoNotDisturbMode = getDoNotDisturb();
        this.isDoNotDisturbMode = false
      } catch (error) {
        console.warn('检查免打扰模式失败:', error)
        this.isDoNotDisturbMode = false
      }
    } else {
      this.isDoNotDisturbMode = false
    }
  }

  public static getInstance(): NotificationManager {
    if (!NotificationManager.instance) {
      NotificationManager.instance = new NotificationManager()
    }
    return NotificationManager.instance
  }

  /**
   * 设置默认图标
   */
  public setDefaultIcon = (iconPath: string): void => {
    this.defaultIcon = iconPath
  }

  /**
   * 设置应用焦点状态
   */
  public setApplicationFocused = (focused: boolean): void => {
    this.isAppFocused = focused
  }

  /**
   * 检查是否可以显示通知
   */
  public canShowNotification = async (): Promise<boolean> => {
    // 检查应用状态和系统设置
    if (this.isDoNotDisturbMode) {
      // 系统免打扰模式开启时可能不应显示通知
      return false
    }

    // 检查权限
    return await checkNotificationPermission()
  }

  /**
   * 显示系统通知
   */
  public showNotification = async (
    config: NotificationConfig,
    handlers?: NotificationHandlerMap,
    id?: string
  ): Promise<string> => {
    // 检查是否应该显示通知
    const canShow = await this.canShowNotification()
    if (!canShow) {
      console.warn('通知权限检查失败或系统免打扰模式开启，无法显示通知')
      // 返回空ID表示通知无法显示
      return ''
    }

    try {
      // 优先使用用户提供的图标，如果没有再使用默认图标
      const notificationConfig = {
        ...config
      }

      // 只有当用户没有提供图标时才使用默认图标
      if (!config.icon && this.defaultIcon) {
        notificationConfig.icon = this.defaultIcon
        console.log('使用默认图标:', this.defaultIcon)
      } else if (config.icon) {
        console.log('使用用户提供图标:', config.icon)
      }

      // 基于应用状态调整通知配置
      if (!this.isAppFocused) {
        // 应用不在前台时可能需要调整通知行为
        // 例如，确保通知有声音提醒（除非明确要求静音）
        if (notificationConfig.silent === undefined) {
          notificationConfig.silent = false
        }

        // 在Windows平台上，当应用不在前台时可能需要特别处理
        if (process.platform === 'win32') {
          notificationConfig.timeoutType = notificationConfig.timeoutType || 'default'
        }
      } else {
        // 在macOS上，应用在前台时也显示通知
        if (process.platform === 'darwin') {
          // 除非明确设置了silent，否则保持非静音
          if (notificationConfig.silent === undefined) {
            notificationConfig.silent = false
          }
        }
      }

      // 创建通知
      const notification = createNotification(notificationConfig)

      // 生成唯一ID
      const notificationId =
        id || `notification_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`

      // 注册事件处理器
      if (handlers) {
        registerNotificationListeners(notification, handlers)
      }

      // 添加平台特定事件处理
      if (process.platform === 'win32') {
        // Windows平台可能需要特殊处理通知点击
        notification.on('click', () => {
          // 确保应用窗口在被点击时会被激活
          const mainWindow = BrowserWindow.getAllWindows().find((win) => !win.isDestroyed())
          if (mainWindow) {
            if (mainWindow.isMinimized()) mainWindow.restore()
            mainWindow.focus()
          }
        })
      }

      // 保存活动通知
      this.activeNotifications.set(notificationId, notification)

      // 显示通知
      notification.show()

      // 设置自动清理
      if (config.timeoutType !== 'never') {
        notification.once('close', () => {
          // 清理资源
          this.activeNotifications.delete(notificationId)
          // 移除所有监听器，避免内存泄漏
          notification.removeAllListeners()
        })
      }

      return notificationId
    } catch (error) {
      console.error('显示通知失败:', error)
      return ''
    }
  }

  /**
   * 关闭通知
   */
  public closeNotification = (id: string): boolean => {
    const notification = this.activeNotifications.get(id)
    if (notification) {
      try {
        // 移除所有事件监听器
        notification.removeAllListeners()
        notification.close()
        this.activeNotifications.delete(id)
        return true
      } catch (error) {
        console.error('关闭通知失败:', error)
        // 尝试清理记录，即使关闭失败
        this.activeNotifications.delete(id)
        return false
      }
    }
    return false
  }

  /**
   * 向渲染进程发送通知
   */
  public sendToRenderer = (
    window: BrowserWindow | null,
    notification: NotificationConfig
  ): void => {
    sendNotificationToRenderer(window, 'notification-received', notification)
  }

  /**
   * 获取所有活动通知ID
   */
  public getActiveNotificationIds = (): string[] => {
    return Array.from(this.activeNotifications.keys())
  }

  /**
   * 关闭所有通知
   */
  public closeAllNotifications = (): void => {
    this.activeNotifications.forEach((notification) => {
      notification.close()
    })
    this.activeNotifications.clear()
  }

  /**
   * 检查特定平台是否支持某个通知特性
   */
  public isFeatureSupported = (feature: string): boolean => {
    switch (feature) {
      case 'actions':
        // 操作按钮支持
        return process.platform === 'darwin' || process.platform === 'win32'

      case 'reply':
        // 直接回复功能支持
        return process.platform === 'darwin'

      case 'sound':
        // 声音支持
        return process.platform === 'darwin' || process.platform === 'win32'

      case 'silent':
        // 静默通知支持
        return true // 所有平台都支持

      case 'urgency':
        // 紧急程度支持
        return process.platform === 'linux'

      case 'icon':
        // 图标支持
        return true // 所有平台都支持，但显示方式不同

      default:
        return false
    }
  }

  /**
   * 清理资源
   */
  public cleanup = (): void => {
    this.closeAllNotifications()
    console.log('Notification Manager cleanup completed')
  }
}

/**
 * 获取通知管理器实例的工厂函数
 */
export const getNotificationManager = (): NotificationManager => {
  return NotificationManager.getInstance()
}
